#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#include "filedispat.h"
#include "data_packet.h"
#include "fidata_list.h"

#define BUFSIZE 	4096
#define NAMESIZE 	10
#define QUIT		"quit"

static int sockfd;
fidata_node *fi_head;
extern chat_packet packet;
int num=0;
static int signal=1;
char name[1024];

static int pthread_reception_mark;

void Task_end_printf(int a);

void perr_exit(const char *str)
{
	perror(str);
	exit(1);
}

void Chatinfo_receive(int fd)
{
	int ret;
	char buf[SOCK_BUF_SIZE];
	ret = readn(fd,buf,SOCK_BUF_SIZE-1);
	if(ret==-1)
		perr_exit("recv=-1");
	if(ret==0){
		close(fd);
		exit(1);
	}
	printf("\n-------------------------------------\n");
	printf("%s\n",buf);
	printf("-------------------------------------\n");	
}

void Errinfo_recvie(int fd)
{
	int ret;
	char buf[SOCK_BUF_SIZE];
	signal = 0;
	ret = readn(fd,buf,SOCK_BUF_SIZE-1);
	if(ret == -1)
		exit(1);
	if(ret==0){
		close(fd);
		exit(1);
	}
	printf("\n-------------------------------------\n");
	printf("%s\n",buf);
	printf("-------------------------------------\n");
}

void REGinfo_recvie(int fd)
{
	int ret;
	char buf[SOCK_BUF_SIZE];
	ret = readn(fd,buf,SOCK_BUF_SIZE-1);
	num++;
	if(ret==-1)
		exit(1);
	if(ret==0){
		close(fd);
		exit(1);
	}
	printf("\n-------------------------------------\n");
	printf("%s\n",buf);
	printf("-------------------------------------\n");
}

void FILEinfo_recvie(int fd)
{
	int ret,file_fd;
	//int val;
	fidata_node *node = malloc(sizeof(fidata_node));
	char buf[SOCK_BUF_SIZE];
	readn(fd,buf,SOCK_BUF_SIZE-1);
	//printf("%s\n",buf);
	sscanf(buf," %s %s %d",node->name,node->buf,&node->residue_size);
	//printf("%s %s %d\n",node->name,node->buf,node->residue_size);
	ret = judge_user_duplicatefile(node->buf,fi_head);
	if(ret == -1){
		if(strlen(buf)>=60){
			memset(node->buf,0,sizeof(node->buf));
			strcpy(node->buf,"file");
		}
		strcat(node->buf,"_1");
	}
	fidata_node_insertion(node,fi_head);
	//printf("%s\n",node->buf);
	file_fd = open(node->buf,O_RDWR|O_CREAT,0644);
	free(node);
	close(file_fd);
	return ;	
}

void Residual_data_read(int fd)
{
	int file_fd,discard,size;
	char buf[SOCK_BUF_SIZE-1],name[64],file_name[64];
	fidata_node *node = malloc(sizeof(fidata_node));
	readn(fd,buf,(SOCK_BUF_SIZE-1));
	sscanf(buf,"%s %s",name,file_name);
	discard = strlen(name)+strlen(file_name)+2;
	node = list_return_filename(name , fi_head);
	if(node == NULL){
		return ;
	}
	//printf("#");
	file_fd = open(node->buf,O_WRONLY);
	if(file_fd == -1){
		perror("read:");
	}
	lseek(file_fd,0,SEEK_END);
	if(node->residue_size > (SOCK_BUF_SIZE-discard)-1){
		//printf("%s",buf+discard);
		size = writen(file_fd, buf+discard, SOCK_BUF_SIZE-discard-1);
		if(size == -1)
			perror("write file:");
		node->residue_size -= (SOCK_BUF_SIZE-discard-1);
	}else{
		//printf("%s",buf+discard);
		size = writen(file_fd,buf+discard,node->residue_size);
		if(size == -1)
			perror("write file:");
		node->residue_size = 0;
		printf("File %s of %s has been transferred!\n",node->buf,node->name);
		free_file_data(node);
	}
	close(file_fd);
	return ;
}

void *thrd_rev_ser(void *arg)
{
	int ret,mark;
	while(1){
		memset(buf,0,SOCK_BUF_SIZE);
		ret = recv(sockfd,buf,1,0);
		if(ret==-1)
			perr_exit("recv=-1");
		if(ret==0){
			close(sockfd);
			exit(1);
		}
		sscanf(buf,"%d",&mark);
		if(mark==CHAT_INFO)
			Chatinfo_receive(sockfd);
		else if(mark == ERR_INFO)
			Errinfo_recvie(sockfd);
		else if(mark==REG_INFO)
			REGinfo_recvie(sockfd);
		else if(mark==FIDA_INFO)
			FILEinfo_recvie(sockfd);
		else if(mark==FILE_INFO){
			Residual_data_read(sockfd);
			continue;
		}
		Task_end_printf(pthread_reception_mark);	
	}
	pthread_exit(NULL);
}

void Select_File_Sending()
{
	char buf[64];
	char data_buf[SOCK_BUF_SIZE];
	int file_fd;
	filestruct *data = malloc(sizeof(filestruct));
	memset(data,0,sizeof(filestruct));
	data->mark = 5;
	signal = 0;
	do{
		printf("Please select the user you want to send to:");
		fflush(stdout);
		fscanf(stdin,"%s",buf);
		data->name_size = strlen(buf);
		data->target_user = (char *)malloc(strlen(buf));
		strncpy(data->target_user,buf,data->name_size);
		memset(buf,0,sizeof(buf));
		if((strncmp(QUIT,buf,strlen(QUIT)))==0)
				return ;
		printf("Please enter a file name:");
		fflush(stdout);
		fscanf(stdin,"%s",buf);
		if((strncmp(QUIT,buf,strlen(QUIT)))==0)
				return ;
		data->file_size = strlen(buf);
		data->filename = (char *)malloc(strlen(buf));
		strncpy(data->filename,buf,data->file_size);
		data->fd_size = get_filesize(buf, &file_fd);
		memset(buf,0,sizeof(buf));
		send_file_data(sockfd,data_buf,data,user.name);
		sleep(1);
	}while(signal);
	send_file(sockfd,file_fd, data->fd_size,data,user.name);
	signal = 0;
	close(file_fd);
		
}

void Task_end_printf(int a)
{
	//printf("test begin\n");
	if(a == 1){
		printf("import 1.Public chat\nimport 2.private chat\n");
		printf("import 3.Sends a file to the specified user\n");
		fflush(stdout);
	}else if(a == 2){
		printf("Please send your group message:");
		fflush(stdout);
	}else if(a == 3){
		printf("Please select user:");
		fflush(stdout);
	}else if(a == 4){
		printf("Please enter a message to send:");
		fflush(stdout);
	}else
		return ;
	return ;
}

int main(int argc, char *argv[])
{
   pthread_t tid;
   int ret;
   char sbuf[BUFSIZE],discard;
    struct sockaddr_in servaddr;
    int port;
    char *ip_addr;
    if(argc !=3){
		printf("Parameter input is abnormal\n");
		return 0;
	}else{
		port = atoi(argv[2]);
		ip_addr=argv[1];
	}
	pthread_reception_mark = 0;
	fi_head = file_list_init(); 		
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, ip_addr, &servaddr.sin_addr);
    servaddr.sin_port = htons(port);

    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	
    if ((ret=pthread_create(&tid,NULL,thrd_rev_ser,NULL))!=0){
	 fprintf(stderr, "pthread_create error:%s\n", strerror(ret));
		exit(1);
    	}

	while(1){
		int module;
	if(num == 0){
			printf("------------Please register your information------------\n");
			printf("Please enter your user name:");
			fscanf(stdin,"%s",user.name);
			//printf("%s\n",user.name);
			sprintf(sbuf,"%d %d %s",0,sockfd,user.name);
			writen(sockfd,sbuf,sizeof(sbuf));
			//printf("%s\n",sbuf);
			sleep(1);
			printf("Wait for a moment, please; Just a moment, please");
			printf("  OK\n");
		}
	if(num!=0){
			printf("$$$$$$$$$Please select your chat mode$$$$$$$$$$$$$$\n");
		while(1){
			module = 0;
			pthread_reception_mark = 1;
			printf("import 1.Public chat\nimport 2.private chat\n");
			printf("import 3.Sends a file to the specified user\n");
			//fscanf(stdin,"%c",&discard);
			fflush(stdout);
			fscanf(stdin,"%d",&module);
			fflush(stdout);
			if(module==1)
			{
				printf("The current mode is public chat. Enter 'quit' to select a new mode\n");
				while(1){
					pthread_reception_mark = 2;
					printf("Please send your group message:");
					memset((char*)public_cat.buff,0,sizeof(public_cat.buff));
					fscanf(stdin,"%[^\n]",public_cat.buff);
					fscanf(stdin,"%c",&discard);
					if(!strlen(public_cat.buff))
						continue;
					if((strncmp(QUIT,public_cat.buff,strlen(QUIT)))==0)
						break;
					//sprintf(sbuf,"%d %s",1,public_cat.buff);
					bzero((char*)sbuf,sizeof(sbuf));
					strcpy(name,user.name);
					sprintf(sbuf,"%d %s",1,strcat(strcat(name,":"),public_cat.buff));
					//printf("............%s...............\n",name);
					writen(sockfd,sbuf,4096);
					
				}
				continue;
			}else if(module==2){
				printf("The current mode is private chat. Enter 'quit' to select a new mode\n");
				while(1){
					pthread_reception_mark = 3;
					printf("Please select user:");
					fscanf(stdin,"%s",packet.tar_name);
					if((strncmp(QUIT,packet.tar_name,strlen(QUIT)))==0)
						break;
					while(1){
						bzero((char*)sbuf,sizeof(sbuf));
						bzero((char*)packet.buff,sizeof(packet.buff));
					    pthread_reception_mark = 4;
						printf("Please enter a message to send:");
						fscanf(stdin,"%[^\n]",packet.buff);
						fscanf(stdin,"%c",&discard);
						if(!strlen(packet.buff))
							continue;
						//printf("&&%s&&\n",packet.buff);
						if((strncmp(QUIT,packet.buff,strlen(QUIT)))==0)
							break;
						strcpy(name,user.name);
						sprintf(sbuf,"%d %s %s",2,packet.tar_name,strcat(strcat(name,":"),packet.buff));
						writen(sockfd,sbuf,sizeof(sbuf));
					}
				}
				continue;
			}else if(module==3){
				Select_File_Sending();
				continue;
			}else{
				printf("The schema does not exist. Please re-select it!!!\n");
				continue;
			}
				}
		}
		
	}
	close(sockfd);
    return 0;
}

